//! 参见[`System`]

use crate::{
    block::Block, board::World, geometry::Coord, level::Level, moment::Moment, render::Renderer,
};
use itertools::Itertools;
use slotmap::{new_key_type, SlotMap};
use std::pin::Pin;

new_key_type!(
    pub struct BlockID;
);

/// 管理方块，并控制显示的上层逻辑。同时可连通盘面逻辑。
pub struct System {
    size: Coord,
    renderer: Renderer,
    block: SlotMap<BlockID, Block>,
}

impl System {
    pub fn new(size: Coord) -> Self {
        Self {
            size,
            renderer: Renderer::new(size).expect("初始化失败"),
            block: SlotMap::with_key(),
        }
    }

    pub fn spawn_effect(&self) -> bool {
        self.block.values().any(Block::is_new)
    }

    /// 执行一次操作
    ///
    /// 显示动画，并更新状态。可以控制是否执行块的生成。
    /// 不执行删除。
    pub async fn run(&mut self, spawn: bool, stop: Pin<&mut impl Moment>) {
        let blocks = self
            .block
            .values_mut()
            .filter(|block| spawn || !block.is_new())
            .collect_vec();
        self.renderer
            .anim_blocks(blocks.iter().map(|block| &**block), stop)
            .await
            .expect("显示失败");
        blocks.into_iter().for_each(Block::run);
    }

    pub fn show_score(&mut self, score: u64, over: bool) {
        self.renderer
            .score(self.size, score, over)
            .expect("显示分数失败");
    }

    /// 把要删除的删了。和显示无关。
    pub fn do_remove(&mut self) {
        self.block.retain(|_, block| !block.will_remove());
    }

    /// 清除一切块。不会显示
    pub fn clear(&mut self) {
        self.block.clear();
    }

    pub fn size(&self) -> Coord {
        self.size
    }
}

impl World for System {
    type Block = BlockID;

    fn spawn(&mut self, pos: Coord, level: Level) -> Self::Block {
        self.block.insert(Block::new(pos, level))
    }

    fn swipe(&mut self, block: Self::Block, dst: Coord, eliminate: bool) {
        let block = &mut self.block[block];
        block.to(dst);
        if eliminate {
            block.eliminate();
        }
    }
}
